EventBridge と Lambda 関数を利用して、EC2 の停止/削除時に EBS スナップショットを自動取得してみた

EventBridge と Lambda 関数を利用して、EC2 の停止/削除時に EBS スナップショットを自動取得してみた

Clock Icon2024.09.10

はじめに

テクニカルサポートの 片方 です。
EC2 インスタンスを意図せず「削除」又は「停止」していた際に、自動で EC2 インスタンスにアタッチしていた EBS(ルートボリューム含む)のスナップショットを取得するカスタムソリューションを実装してみました。
大まかな流れは以下です。

  1. EventBridge で EC2 インスタンスの状態変化を監視します。
  2. "stopping" 又は、"shutting-down" 状態になった場合、Lambda 関数を呼び出します。
  3. 全ての EBS のスナップショットを取得します。

なお、Lambda 関数を実装せずとも、オートメーションランブックの "AWS-CreateSnapshot" を呼び出せばよいのではと思うかもしれません。
しかしながら、当該ランブックでは複数の EBS を対象に実行できないため、複数の EBS に対応可能な(スナップショット取得) Lambda 関数を作成しました。

実装してみた

以下の順番で実装します。

  • 実行ロール
  • Lambda 関数
  • EventBridge

実行ロール

※ 信頼関係

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

アタッチするポリシー例

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeSnapshots",
                "ec2:DescribeVolumes",
                "ec2:CreateSnapshot",
                "ec2:CreateVolume",
                "ec2:AttachVolume",
                "ec2:DetachVolume",
                "ec2:DeleteVolume"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:<region>:<account-id>:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:<region>:<account-id>:log-group:/aws/lambda/<function-name>:*"
            ]
        }
    ]
}

※ 適宜修正してください。

Lambada 関数

Python 3.12 で作成しました。
実行ロールでは、既存のロールを使用するを選択し、先ほど作成したロールを指定します。

実装する Lambda 関数例
import boto3

ec2 = boto3.client('ec2')

def lambda_handler(event, context):
    # イベントの内容に基づいて、EC2インスタンスIDを取得
    instance_id = event['detail']['instance-id']
    print(f"EC2 Instance ID: {instance_id} is stopping. Creating snapshots...")

    # EC2インスタンスにアタッチされているEBSボリュームを取得
    volumes = ec2.describe_volumes(
        Filters=[{
            'Name': 'attachment.instance-id',
            'Values': [instance_id]
        }]
    )

    # それぞれのボリュームのスナップショットを作成
    for volume in volumes['Volumes']:
        volume_id = volume['VolumeId']
        print(f"Creating snapshot for Volume ID: {volume_id}")

        snapshot = ec2.create_snapshot(
            VolumeId=volume_id,
            Description=f"Snapshot of {volume_id} from instance {instance_id}"
        )
        print(f"Snapshot created: {snapshot['SnapshotId']}")

    return {
        'statusCode': 200,
        'body': 'Snapshots created successfully.'
    }

※ 適宜修正してください。

EventBridge

EventBridge のマネジメントコンソール画面より、左ペインのルールを選択し、「ルールを作成」をクリックします。

01

EventBridge の名前を入力し、「イベントパターンを持つルール」を選択します。

02

下部へスクロールを行い、作成のメソッドを「パターンフォームを使用する」を選択します。

03

04

イベントパターンのセクションで、以下の設定を行います。

  • イベントソース: AWS のサービス
  • AWS のサービス: EC2
  • イベントタイプ: EC2 Instance State-change Notification
  • イベントタイプの仕様 1: 特定の状態
  • 特定の状態: shutting-down , stopping

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-event-patterns.html

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-lifecycle.html

無題

05

ターゲットを選択において、以下の設定を行います。

  • ターゲットタイプ: AWS のサービス
  • ターゲットを選択: Lambda 関数
  • 関数: 前途で作成した Lambda 関数を指定

06

後は、そのまま進めて「ルールの作成」を行えば全ての実装は終了です。

検証してみた

EC2 インスタンスを起動させて適当な EBS を複数アタッチします。

07

停止させます。

08
09

インスタンスの状態が「停止済み」になったら、スナップショットが取得されているか確認します。

10

問題なく全ての EBS のスナップショットが取得されていました。

11

今度は、削除して取得されるか確認します。

12
13

インスタンスの状態が「停止済み」になったら、スナップショットが取得されているか確認します。
14

こちらも、取得できました
成功です!

15

まとめ

本ブログが誰かの参考になれば幸いです。

参考資料

アノテーション株式会社について

アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.